﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using MazeBuilder;
using MazeBuilder.Entities;
using MazeBuilder.Entities.Tiles;
using MazeVisualizer.Images;
using RoomModuleCatalog;
using System.Linq;

namespace MazeVisualizer
{
  public partial class MazeVisualizer : Form
  {
    private MazeBuilder.MazeBuilder _builder;

    public MazeVisualizer() {
      InitializeComponent();
    }

    private void renderMaze(Maze maze) {
      builded = 0;
      Image img = new Bitmap((maze.tiles[0].GetLength(0) + 1) * 32,
                             (maze.tiles.GetLength(0) + 1) * 32);
      var g = Graphics.FromImage(img);

      for (var i = 0; i < maze.tiles[0].GetLength(0); i++) {
        for (var j = 0; j < maze.tiles.GetLength(0); j++) {
          try {
            g.DrawImage(GetImageByType(maze.tiles[j][i]), new RectangleF(32 * i, 32 * j, 32, 32), new RectangleF(0, 0, 32, 32), GraphicsUnit.Pixel);
          }
          catch (Exception e) {
            Console.WriteLine(e);
          }
        }
      }

      pictureBox1.Image = ResizeImage(img, new Size(1024, 768));
      MessageBox.Show(Resources.MazeVisualizer_renderMaze_Build_complete);
    }

    public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = true) {
      int newWidth;
      int newHeight;
      if (preserveAspectRatio) {
        var originalWidth = image.Width;
        var originalHeight = image.Height;
        var percentWidth = size.Width / (float)originalWidth;
        var percentHeight = size.Height / (float)originalHeight;
        var percent = percentHeight < percentWidth ? percentHeight : percentWidth;
        newWidth = (int)(originalWidth * percent);
        newHeight = (int)(originalHeight * percent);
      }
      else {
        newWidth = size.Width;
        newHeight = size.Height;
      }
      Image newImage = new Bitmap(newWidth, newHeight);
      using (var graphicsHandle = Graphics.FromImage(newImage)) {
        graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
      }
      return newImage;
    }

    private static Image GetImageByType(Tile tile) {
      Bitmap image = null;
      if (tile is WallTile)
        image = Resources.wall;

      else if (tile is NullTile)
        image = Resources._void;

      else if (tile is DoorTile)
        image = Resources.door;

      else if (tile is VoidTile)
        image = Resources._void;

      else if (tile is SkullTile)
        image = Resources.skull;

      else if (tile is SpadeTile)
        image = Resources.spades;

      else if (tile is FountainTile)
        image = Resources.fountain;

      else if (tile is FlameTile)
        image = Resources.flame2;

      else if (tile is PentagramTile)
        image = Resources.pentagram;

      else if (tile is FloorTile)
        image = Resources.floor;

      return image;
    }

    private int builded;
    const string ROOM_PATTERNS = "../../../../MoreRogueLike/MoreRogue.Test/IntegrationConfigurations/RoomPatterns/";

    private void button_Click(object sender, EventArgs e) {

#if DEBUG
          var MAX_ROOM_NUMBER = StaticRandomNumberGenerator.Next(1, 1);
#endif

#if !DEBUG
      var MAX_ROOM_NUMBER = StaticRandomNumberGenerator.Next((int) numericUpDownMin.Value, (int) numericUpMax.Value);
#endif

      builded = 0;
      Refresh();

      _builder = new MazeBuilder.MazeBuilder();
      _builder.oneBuilded += OnBuilderOnOneBuilded;
      _builder.builded += OnBuilded;

      var config = new MazeConfiguration(13, 7, MAX_ROOM_NUMBER) { RoomPatternsPath = ROOM_PATTERNS };

      var maze = _builder.BuildMaze(config);

      var task = new Task(() => { builded = 0; renderMaze(maze); });
      task.Start();

    }

    private void OnBuilded(object sender, BuildedArgs args) {
      builded = 0;
      _builder.builded -= OnBuilded;
      _builder.oneBuilded -= OnBuilderOnOneBuilded;
    }

    private void OnBuilderOnOneBuilded(object o, oneBuildedArgs args) {
      builded++;
      lblBuilded.Text = string.Format("Builded: {0}", builded);
      Refresh();
    }

    private void MazeVisualizer_Load(object sender, EventArgs e) {
      button1.Location = new Point(Width - button1.Width - 20, 12);
      button2.Location = new Point(Width - button1.Width - button2.Width - 20, 12);
      groupBox1.Location = new Point(Width - button1.Width - button2.Width - groupBox1.Width - 40, 1);
    }

    private static void SavePicture(Image img) {
      var now = DateTime.Now;
      var date = string.Format("maze/snap_Date_{0}_Time_{1}.png", now.ToLongDateString().Replace(" ", string.Empty),
                               now.ToLongTimeString().Replace(":", "_"));

      var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
      var directories = Directory.GetDirectories(folderPath);
      var mazeDir = directories.SingleOrDefault(x => x == "maze");
      if (string.IsNullOrEmpty(mazeDir))
        Directory.CreateDirectory(String.Format("{0}/maze", folderPath));

      img.Save(Path.Combine(folderPath, date), ImageFormat.Png);
      MessageBox.Show(string.Format("Picture saved to {0}", Path.Combine(folderPath, date)));
    }

    private void saveShot_Click(object sender, EventArgs e) {
      SavePicture(pictureBox1.Image);
    }
  }
}
